# -*- coding: utf-8 -*-
# @Author  : wyh
# @Time    : 2022/7/15 16:14
# @File    : tdengine
# @Email   : 2448979539@qq.com
import logging
# logging：用于记录日志。
from threading import Lock  # 用于线程同步。
from django.conf import settings  # Django的配置文件，用于获取项目设置。
from common.universal_object_pool import ObjectPool, AbstractObject, _ObjectContext  # 自定义的通用对象池管理模块。


# 尝试导入taos模块，如果失败，则定义一个EntryObj类，该类的实例在尝试访问任何属性时都会返回None，并且打印错误信息。
try:
    # 做涛思加载缺少依赖库兼容, 仅能解决项目初始化运行, 该报错还是会报错
    import taos
except Exception as e:
    class EntryObj:
        def __getattr__(self, item):
            return None


    print(f'导入taos错误: {e}')
    taos = EntryObj()
# 创建一个锁对象，用于同步访问共享资源。
lock = Lock()

# TdengineContextHelper类继承自_ObjectContext，用于提供with语句的上下文管理。它重写了__enter__方法，返回一个TDengine游标对象。
# 泛型类, 用于with语句提示, 无实际意义
class TdengineContextHelper(_ObjectContext):

    def __enter__(self) -> taos.TaosCursor:
        return super().__enter__()

# TdenginePool类继承自ObjectPool，用于管理TDengine数据库连接池。它重写了get方法，返回一个TdengineContextHelper对象。
# 增加泛型, 用于with语句提示, 无实际意义, 可直接使用ObjectPool
class TdenginePool(ObjectPool):

    def get(self, block=True, timeout=None) -> TdengineContextHelper:
        return super().get(block, timeout)

# TdengineOperator类继承自AbstractObject，用于创建和管理TDengine数据库连接。
class TdengineOperator(AbstractObject):
    error_type_list_set_not_available = []  # 出了特定类型的错误，可以设置对象已经无效不可用了，不归还到队列里面。
    # __init__方法初始化数据库连接。
    def __init__(self, host='192.168.100.251', user='root', password='taosdata', database='wlw'):
            super().__init__()
            self.conn = taos.connect(host=host, user=user, password=password, database=database)
            self.logger = logging.getLogger(self.__class__.__name__)

    """ 下面3个是重写的方法"""
# clean_up方法在对象被销毁前关闭数据库连接。
    def clean_up(self):  # 如果一个对象最近30分钟内没被使用，那么对象池会自动将对象摧毁并从池中删除，会自动调用对象的clean_up方法。
        self.conn.close()
# before_use方法在使用对象前创建一个新的游标。
    def before_use(self):
        self.cursor = self.conn.cursor()
        self.core_obj = self.cursor  # 这个是为了operator对象自动拥有cursor对象的所有方法。
# before_back_to_queue方法在对象返回到对象池前关闭游标。
    def before_back_to_queue(self, exc_type, exc_val, exc_tb):
        self.cursor.close()  # 也可以不要，因为每次的cursor都是不一样的。

# PoolMap类用于存储和管理数据库连接池实例。
class PoolMap(object):
    __instance = {}
    __lock = Lock()

    @classmethod
    def get_instance(cls, key):
        return cls.__instance.get(key, None)

    @classmethod
    def set_instance(cls, key, value):
        cls.__instance[key] = value


# 根据setting获取默认超级表
def get_stable_name(db='default'):
    return settings.TDENGINES[db]['STABLE']


# 根据config, 获取连接
def get_tdengine_pool(host, user, password, database, *, object_pool_size=10, **kwargs) -> TdenginePool:
    key = (host, user, password, database, object_pool_size)
    with lock:
        if not PoolMap.get_instance(key):
            PoolMap.set_instance(key, TdenginePool(object_type=TdengineOperator, object_pool_size=object_pool_size,
                                                   object_init_kwargs={'host': host, 'user': user,
                                                                       'password': password,
                                                                       'database': database}))
    return PoolMap.get_instance(key)


# 根据setting配置项获取连接
def load_tdengine_pool(db='default', *, object_pool_size=10, no_db=False) -> TdenginePool:
    db_config = settings.TDENGINES[db]
    result = get_tdengine_pool(
        host=db_config['HOST'],
        user=db_config['USER'],
        password=db_config['PASSWORD'],
        database=None if no_db else db_config['DATABASE'],
        object_pool_size=object_pool_size
    )
    return result
